//todo ---------------------------  插件安装  ----------------------------------
//  yarn add vant-weapp --production
//todo ---------------------------  自定义组件  ----------------------------------
// 类似于页面，一个自定义组件由 json wxml wxss js 4个文件组成。要编写一个自定义组件
// 首先需要在 json 文件中进行自定义组件声明（将 component 字段设为 true 可将这一组文件设为自定义组件）：
// {
//     "component": true,
//     "usingComponents": {
//       "van-toast": "/components/vant-weapp/toast/index",
//       "van-divider": "/components/vant-weapp/divider/index"
//     },
//     "backgroundTextStyle": "light",
//     "navigationBarBackgroundColor": "#004B97",
//     "backgroundColor": "#FFFFFF",
//     "navigationBarTitleText": "洲博通物流",
//     "navigationBarTextStyle": "white",
//     "navigationStyle": "default",
//     "enablePullDownRefresh":false
//   }

//   <!-- 这是自定义组件的内部WXML结构 -->
// <view class="inner">
//   {{innerText}}
// </view>
// <slot></slot>

// /* 这里的样式只应用于这个自定义组件 */
// .inner {
//   color: red;
// }

//   注意：在组件wxss中不应使用ID选择器、属性选择器和标签名选择器。
// 在自定义组件的 js 文件中，需要使用 Component() 来注册组件，并提供组件的属性定义、内部数据和自定义方法。
// 组件的属性值和内部数据将被用于组件 wxml 的渲染，其中，属性值是可由组件外部传入的。更多细节参见 Component构造器 。
// {/* <view bindtap='onTap'   class="container"></view> */}
// this.triggerEvent('getUserInfo',e.detail,{})  //触发父组件回调
// this.trigger('getUserInfo',e.detail,{})
// behavior  行为   behavior.js中
// attached: function()
//datached:function(){} 页面注销时候


//todo slot 插槽 [见bookdetail.wxml  tag.html tag.js ]   配置插槽启用多slot支持 options: {multipleSlots: true}, multipleSlots: true
//todo kim-stamp 使用外来样式   externalClasses: ["tag-class"],          [在components/tag/tag.js]
// Component({
//   options: {
//     multipleSlots: true,            // 在组件定义时的选项中启用多slot支持
//     styleIsolation: 'apply-shared',      //指定特殊的样式隔离选项 ----isolated|apply-shared|shared apply-shared 表示页面 wxss 样式将影响到自定义组件，但自定义组件 wxss 中指定的样式不会影响页面；solated 表示启用样式隔离，在自定义组件内外，使用 class 指定的样式将不会相互影响（一般情况下的默认值）；shared 表示页面 wxss 样式将影响到自定义组件，自定义组件 wxss 中指定的样式也会影响页面和其他设置了 apply-shared 或 shared 的自定义组件。（这个选项在插件中不可用。）
//   },
//   externalClasses: ["tag-class"],ss
//   properties: { /* ... */ },
//   methods: { /* ... */ }
// })

// Component({
//     behaviors: [],        // 类似于mixins和traits的组件间代码复用机制，参见 behaviors https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/behaviors.html
//     externalClasses:[],   // 组件接受的外部样式类， 类型 String Array， 参见 外部样式类 https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/wxml-wxss.html
//     options:{},           // 一些选项（文档中介绍相关特性时会涉及具体的选项设置，这里暂不列举）
//     options: {
//      multipleSlots: true,            // 在组件定义时的选项中启用多slot支持
//      styleIsolation: 'apply-shared',      //指定特殊的样式隔离选项 ----isolated|apply-shared|shared apply-shared 表示页面 wxss 样式将影响到自定义组件，但自定义组件 wxss 中指定的样式不会影响页面；solated 表示启用样式隔离，在自定义组件内外，使用 class 指定的样式将不会相互影响（一般情况下的默认值）；shared 表示页面 wxss 样式将影响到自定义组件，自定义组件 wxss 中指定的样式也会影响页面和其他设置了 apply-shared 或 shared 的自定义组件。（这个选项在插件中不可用。）
//    },
//     properties: {   // 组件的对外属性，是属性名到属性设置的映射表
//       myProperty: {
//         type: String,               //属性的类型
//         value: '',                  //属性的初始值
//         optionalTypes:[],           //属性的类型（可以指定多个）
//         observer:function(){}       //属性值变化时的回调函数
//       },
//       myProperty2: String // 简化的定义方式
//     },

//     data: {}, // 私有数据，可用于模板渲染

//     observers:{}, //组件数据字段监听器，用于监听 properties 和 data 的变化，参见 数据监听器 https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/observer.html

//     methods: { //组件的方法，包括事件响应函数和任意的自定义方法，关于事件响应函数的使用，参见 组件间通信与事件
//         onMyButtonTap: function(){
//           this.setData({
             // 更新属性和数据的方法与更新页面数据的方法类似
//           })
//         },
         // 内部方法建议以下划线开头
//         _myPrivateMethod: function(){
//           this.setData({
//             'A[0].B': 'myPrivateData'
//           })
//         },
//         _propertyChange: function(newVal, oldVal) { }
//     },

//     created:function(){},         //组件生命周期函数-在组件实例刚刚被创建时执行，注意此时不能调用 setData )
//     attached:function(){},        //组件生命周期函数-在组件实例进入页面节点树时执行)
//     ready:function(){},           //组件生命周期函数-在组件布局完成后执行)
//     moved:function(){},           //组件生命周期函数-在组件实例被移动到节点树另一个位置时执行)
//     ready:function(){},           //组件生命周期函数-在组件布局完成后执行)
//     moved:function(){},           //组件生命周期函数-在组件实例被移动到节点树另一个位置时执行)
//     detached:function(){},        //组件生命周期函数-在组件实例被从页面节点树移除时执行)

//     definitionFilter:{},          //定义段过滤器，用于自定义组件扩展，参见 自定义组件扩展
//     relations: {},                //组件间关系定义，参见 组件间关系 https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/relations.html

//     组件生命周期声明对象，参见 组件生命周期 https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/lifetimes.html
//     lifetimes: {
       // 生命周期函数，可以为函数，或一个在methods段中定义的方法名
//       attached: function () { },
//       moved: function () { },
//       detached: function () { },
//     },
//     pageLifetimes: {
       // 组件所在页面的生命周期函数
//       show: function () { },
//       hide: function () { },
//       resize: function () { },
//     },
//   })

// 组件样式
// 组件对应 wxss 文件的样式，只对组件wxml内的节点生效。编写组件样式时，需要注意以下几点：
// 组件和引用组件的页面不能使用id选择器（#a）、属性选择器（[a]）和标签名选择器，请改用class选择器。
// 组件和引用组件的页面中使用后代选择器（.a .b）在一些极端情况下会有非预期的表现，如遇，请避免使用。
// 子元素选择器（.a>.b）只能用于 view 组件与其子节点之间，用于其他组件可能导致非预期的情况。
// 继承样式，如 font 、 color ，会从组件外继承到组件内。
// 除继承样式外， app.wxss 中的样式、组件所在页面的的样式对自定义组件无效（除非更改组件样式隔离选项）。
// #a { } /* 在组件中不能使用 */
// [a] { } /* 在组件中不能使用 */
// button { } /* 在组件中不能使用 */
// .a > .b { } /* 除非 .a 是 view 组件节点，否则不一定会生效 */

// todo 监听事件
// 事件系统是组件间通信的主要方式之一。自定义组件可以触发任意的事件，引用组件的页面可以监听这些事件。关于事件的基本概念和用法，参见 事件 。
// 监听自定义组件事件的方法与监听基础组件事件的方法完全一致：
// 代码示例：
// <!-- 当自定义组件触发“myevent”事件时，调用“onMyEvent”方法 -->
// <component-tag-name bindmyevent="onMyEvent" />
// <!-- 或者可以写成 -->
// <component-tag-name bind:myevent="onMyEvent" />
// Page({
//     onMyEvent: function(e){
//       e.detail // 自定义组件触发事件时提供的detail对象
//     }
//   })

//todo 触发事件
// 自定义组件触发事件时，需要使用 triggerEvent 方法，指定事件名、detail对象和事件选项：
// <!-- 在自定义组件中 -->
// <button bindtap="onTap">点击这个按钮将触发“myevent”事件</button>

// Component({
//     methods: {
//       onTap: function(e){
//         this.triggerEvent('customevent', e.detail) // 只会触发 pageEventListener2
//         this.triggerEvent('customevent', {}, { bubbles: true }) // 会依次触发 pageEventListener2 、 pageEventListener1
//         this.triggerEvent('customevent', {}, { bubbles: true, composed: true }) // 会依次触发 pageEventListener2 、 anotherEventListener 、 pageEventListener1
//       }
//     }
//   })
// 触发事件的选项包括：
// 选项名	      类型	     是否必填	默认值	描述
// bubbles	     Boolean	否	      false	  事件是否冒泡
// composed	     Boolean	否	      false	  事件是否可以穿越组件边界，为false时，事件将只能在引用组件的节点树上触发，不进入其他任何组件内部
// capturePhase	 Boolean	否	      false	  事件是否拥有捕获阶段

//todo 组件生命周期
// Component({
//     lifetimes: {
//       attached: function() {
         // 在组件实例进入页面节点树时执行
//       },
//       detached: function() {
         // 在组件实例被从页面节点树移除时执行
//       },
//     },
     // 以下是旧式的定义方式，可以保持对 <2.2.3 版本基础库的兼容
//     attached: function() {
       // 在组件实例进入页面节点树时执行
//     },
//     detached: function() {
      // 在组件实例被从页面节点树移除时执行
//     },
    // ...
//   })

//todo  behaviors Object object
// 定义段	          类型	是否必填	描述	最低版本
// properties	     Object Map	否	同组件的属性
// data	             Object	否	同组件的数据
// methods	         Object	否	同自定义组件的方法
// behaviors	     String Array	否	引入其它的 behavior
// created	         Function	否	生命周期函数
// attached	         Function	否	生命周期函数
// ready	         Function	否	生命周期函数
// moved	         Function	否	生命周期函数
// detached	         Function	否	生命周期函数

// todo 定义和使用组件间关系
// <custom-ul>
//   <custom-li> item 1 </custom-li>
//   <custom-li> item 2 </custom-li>
// </custom-ul>

// 这个例子中， custom-ul 和 custom-li 都是自定义组件，它们有相互间的关系，相互间的通信往往比较复杂。
// 此时在组件定义时加入 relations 定义段，可以解决这样的问题。示例：

// path/to/custom-ul.js
// Component({
//     relations: {
//       './custom-li': {
//         type: 'child', // 关联的目标节点应为子节点
//         linked: function(target) {
           // 每次有custom-li被插入时执行，target是该节点实例对象，触发在该节点attached生命周期之后
//         },
//         linkChanged: function(target) {
           // 每次有custom-li被移动后执行，target是该节点实例对象，触发在该节点moved生命周期之后
//         },
//         unlinked: function(target) {
           // 每次有custom-li被移除时执行，target是该节点实例对象，触发在该节点detached生命周期之后
//         }
//       }
//     },
//     methods: {
//       _getAllLi: function(){
        // 使用getRelationNodes可以获得nodes数组，包含所有已关联的custom-li，且是有序的
//         var nodes = this.getRelationNodes('path/to/custom-li')
//       }
//     },
//     ready: function(){
//       this._getAllLi()
//     }
//   })

//   path/to/custom-li.js
// Component({
//     relations: {
//       './custom-ul': {
//         type: 'parent', // 关联的目标节点应为父节点
//         linked: function(target) {
           // 每次被插入到custom-ul时执行，target是custom-ul节点实例对象，触发在attached生命周期之后
//         },
//         linkChanged: function(target) {
           // 每次被移动后执行，target是custom-ul节点实例对象，触发在moved生命周期之后
//         },
//         unlinked: function(target) {
          // 每次被移除时执行，target是custom-ul节点实例对象，触发在detached生命周期之后
//         }
//       }
//     }
//   })
//   注意：必须在两个组件定义中都加入relations定义，否则不会生效。

//todo 使用数据监听器
// 例如， this.data.sum 永远是 this.data.numberA 与 this.data.numberB 的和。此时，可以使用数据监听器进行如下实现。
// Component({
//     attached: function() {
//       this.setData({
//         numberA: 1,
//         numberB: 2,
//       })
//     },
//     observers: {
//       'numberA, numberB': function(numberA, numberB) {
           // 在 numberA 或者 numberB 被设置时，执行这个函数
//         this.setData({
//           sum: numberA + numberB
//         })
//       }
//     }
//   })

//todo 监听字段语法
// 数据监听器支持监听属性或内部数据的变化，可以同时监听多个。一次 setData 最多触发每个监听器一次。
// 同时，监听器可以监听子数据字段，如下例所示。
// Component({
//     observers: {
//       'some.subfield': function(subfield) {
          // 使用 setData 设置 this.data.some.subfield 时触发
          // （除此以外，使用 setData 设置 this.data.some 也会触发）
//         subfield === this.data.some.subfield
//       },
//       'arr[12]': function(arr12) {
         // 使用 setData 设置 this.data.arr[12] 时触发
         // （除此以外，使用 setData 设置 this.data.arr 也会触发）
//         arr12 === this.data.arr[12]
//       },
//     }
//   })

//   如果需要监听所有子数据字段的变化，可以使用通配符 **
//   Component({
//     observers: {
//       'some.field.**': function(field) {
           // 使用 setData 设置 this.data.some.field 本身或其下任何子数据字段时触发
           // （除此以外，使用 setData 设置 this.data.some 也会触发）
//         field === this.data.some.field
//       },
//     },
//     attached: function() {
         // 这样会触发上面的 observer
//       this.setData({
//         'some.field': { /* ... */ }
//       })
        // 这样也会触发上面的 observer
//       this.setData({
//         'some.field.xxx': { /* ... */ }
//       })
        // 这样还是会触发上面的 observer
//       this.setData({
//         'some': { /* ... */ }
//       })
//     }
//   })

//    特别地，仅使用通配符 ** 可以监听全部 setData 。

// Component({
//   observers: {
//     '**': function() {
      // 每次 setData 都触发
//     },
//   },
// })

// 组件数据中的纯数据字段
// Component({
//     options: {
//       pureDataPattern: /^_/ // 指定所有 _ 开头的数据字段为纯数据字段
//     },
//     data: {
//       a: true, // 普通数据字段
//       _b: true, // 纯数据字段
//     },
//     methods: {
//       myMethod() {
//         this.data._b // 纯数据字段可以在 this.data 中获取
//         this.setData({
//           c: true, // 普通数据字段
//           _d: true, // 纯数据字段
//         })
//       }
//     }
//   })

//   上述组件中的纯数据字段不会被应用到 WXML 上：
// <view wx:if="{{a}}"> 这行会被展示 </view>
// <view wx:if="{{_b}}"> 这行不会被展示 </view>

//todo 组件属性中的纯数据字段
// 属性也可以被指定为纯数据字段（遵循 pureDataPattern 的正则表达式）。
// 属性中的纯数据字段可以像普通属性一样接收外部传入的属性值，但不能将它直接用于组件自身的 WXML 中。

// Component({
//   options: {
//     pureDataPattern: /^_/
//   },
//   properties: {
//     a: Boolean,
//     _b: {
//       type: Boolean,
//       observer() {
         // 不要这样做！这个 observer 永远不会被触发
//       }
//     },
//   }
// })
// 注意：属性中的纯数据字段的属性 observer 永远不会触发！如果想要监听属性值变化，使用 数据监听器 代替。
// 使用数据监听器监听纯数据字段
// Component({
//     options: {
//       pureDataPattern: /^timestamp$/ // 将 timestamp 属性指定为纯数据字段
//     },
//     properties: {
//       timestamp: Number,
//     },
//     observers: {
//       timestamp: function () {
         // timestamp 被设置时，将它展示为可读时间字符串
//         var timeString = new Date(this.data.timestamp).toLocaleString()
//         this.setData({
//           timeString: timeString
//         })
//       }
//     }
//   })

//   <view>{{timeString}}</view>

//todo   自定义组件扩展
// behavior.js
// module.exports = Behavior({
//     definitionFilter(defFields) {
//       defFields.data.from = 'behavior'
//     },
//   })

//    component.js
//   Component({
//     data: { from: 'component' },
//     behaviors: [require('behavior.js')],
//     ready() {
//       console.log(this.data.from) // 此处会发现输出 behavior 而不是 component
//     }
//   })
// 通过例子可以发现，自定义组件的扩展其实就是提供了修改自定义组件定义段的能力，上述例子就是修改了自定义组件中的 data 定义段里的内容

// 使用扩展
// Behavior() 构造器提供了新的定义段 definitionFilter ，用于支持自定义组件扩展。
// definitionFilter 是一个函数，在被调用时会注入两个参数，
// 第一个参数是使用该 behavior 的 component/behavior 的定义对象，
// 第二个参数是该 behavior 所使用的 behavior 的 definitionFilter 函数列表。

// 以下举个例子来说明：
// behavior3.js
// module.exports = Behavior({
//     definitionFilter(defFields, definitionFilterArr) {},
// })

// behavior2.js
// module.exports = Behavior({
//   behaviors: [require('behavior3.js')],
//   definitionFilter(defFields, definitionFilterArr) {
     // definitionFilterArr[0](defFields)
//   },
// })

// behavior1.js
// module.exports = Behavior({
//   behaviors: [require('behavior2.js')],
//   definitionFilter(defFields, definitionFilterArr) {},
// })

// component.js
// Component({
//   behaviors: [require('behavior1.js')],
// })

// 下面利用扩展简单实现自定义组件的计算属性功能:
// behavior.js
// module.exports = Behavior({
//   lifetimes: {
//     created() {
//       this._originalSetData = this.setData // 原始 setData
//       this.setData = this._setData // 封装后的 setData
//     }
//   },
//   definitionFilter(defFields) {
//     const computed = defFields.computed || {}
//     const computedKeys = Object.keys(computed)
//     const computedCache = {}

//     计算 computed
//     const calcComputed = (scope, insertToData) => {
//       const needUpdate = {}
//       const data = defFields.data = defFields.data || {}

//       for (let key of computedKeys) {
//         const value = computed[key].call(scope) // 计算新值
//         if (computedCache[key] !== value) needUpdate[key] = computedCache[key] = value
//         if (insertToData) data[key] = needUpdate[key] // 直接插入到 data 中，初始化时才需要的操作
//       }

//       return needUpdate
//     }

//     重写 setData 方法
//     defFields.methods = defFields.methods || {}
//     defFields.methods._setData = function (data, callback) {
//       const originalSetData = this._originalSetData // 原始 setData
//       originalSetData.call(this, data, callback) // 做 data 的 setData
//       const needUpdate = calcComputed(this) // 计算 computed
//       originalSetData.call(this, needUpdate) // 做 computed 的 setData
//     }

//     初始化 computed
//     calcComputed(defFields, true) // 计算 computed
//   }
// })

// 在组件中使用：
// const beh = require('./behavior.js')
// Component({
//   behaviors: [beh],
//   data: {
//     a: 0,
//   },
//   computed: {
//     b() {
//       return this.data.a + 100
//     },
//   },
//   methods: {
//     onTap() {
//       this.setData({
//         a: ++this.data.a,
//       })
//     }
//   }
// })

// <view>data: {{a}}</view>
// <view>computed: {{b}}</view>
// <button bindtap="onTap">click</button>

//todo ---------------------------  事件绑定 或者button微信开放事件  ----------------------------------
// bindtap="onClick"
// bindgetuserinfo="bindGetUserInfo"
// bindcontact="bindContact"
// bindgetphonenumber="bindGetPhoneNumber"
// binderror="bindError"
// bindlaunchapp="bindLaunchApp"
// bindopensetting="bindOpenSetting"

// background - color: #fffbdd !important;  //样式强制覆盖
// wx: for-item= "i" 自定义遍历每一项的名字
// 想要使用&nbsp等html转义，要在标签类设置encode='true'

// scroll-view |Page onReachBottom
// text-indent:2em 首行缩进
// wx.showLoading()  加载小圆圈      wx.hideLoading() 隐藏
// multipleSlots: true
// wx.navigateTo  跳转

// index: {       监听事件改变
// type: String,
//  value:'100',
//     observer: function(newVal, oldVal, changePath) {}
// }

//todo 起别名 wx:for-item="i"
//<view wx:for="{{books}}" wx:key="{{item.artist_id}}" wx:for-item="i">
//<block>
//  <v-book books="{{i}}" />
//</block>
//</view>

// todo startsWith 头的截取          endsWith 尾巴的截取

// todo 引用  WXML 提供两种文件引用方式 import 和 include 。
// import
// import可以在该文件中使用目标文件定义的template，如：
// 在 item.wxml 中定义了一个叫item的template：
// <!-- item.wxml -->
// {/* <template name="item">
//   <text>{{text}}</text>
// </template> */}
// 在 index.wxml 中引用了 item.wxml，就可以使用item模板：
// {/* <import src="item.wxml"/>
// <template is="item" data="{{text: 'forbar'}}"/> */}
// import 的作用域
// import 有作用域的概念，即只会 import 目标文件中定义的 template，而不会 import 目标文件 import 的 template。
// 如：C import B，B import A，在C中可以使用B定义的template，在B中可以使用A定义的template，但是C不能使用A定义的template。
//-------------------------
// include
// include 可以将目标文件除了 <template/> <wxs/> 外的整个代码引入，相当于是拷贝到 include 位置，如：
// <!-- index.wxml -->
// {/* <include src="header.wxml"/>
// <view> body </view>
// <include src="footer.wxml"/> */}

// <!-- header.wxml -->
// {/* <view> header </view> */}
// <!-- footer.wxml -->
// {/* <view> footer </view> */}

// todo --------------------------- 页面配置  ----------------------------------
// todo 每一个小程序页面也可以使用 .json 文件来对本页面的窗口表现进行配置。
// 页面中配置项在当前页面会覆盖 app.json 的 window 中相同的配置项。文件内容为一个 JSON 对象，有以下属性
// "window": {
  // navigationBarBackgroundColor	           HexColor	  #000000	  导航栏背景颜色，如 #000000
  // backgroundColor	                       HexColor	  #ffffff	  窗口的背景色
  // navigationBarTextStyle	                 string	    white	    导航栏标题颜色，仅支持 black / white	
  // navigationBarTitleText	                 string		            导航栏标题文字内容
  // navigationStyle	                       string	    default	  导航栏样式，仅支持以下值：default 默认样式custom 自定义导航栏，只保留右上角胶囊按钮
  // enablePullDownRefresh	                 boolean	  false	    是否开启当前页面下拉刷新。详见 Page.onPullDownRefresh
  // backgroundTextStyle	                   string	    dark	    下拉 loading 的样式，仅支持 dark / light
  // backgroundColorTop	                     string	    #ffffff	  顶部窗口的背景色，仅 iOS 支持	微信客户端 6.5.16
  // backgroundColorBottom	                 string	    #ffffff	  底部窗口的背景色，仅 iOS 支持	微信客户端 6.5.16
  // onReachBottomDistance	                 number	    50	      页面上拉触底事件触发时距页面底部距离，单位为px。详见 Page.onReachBottom
  // pageOrientation	                       string	    portrait	屏幕旋转设置，支持 auto / portrait / landscape 详见 响应显示区域变化	2.4.0 (auto) / 2.5.0 (landscape
  // disableScroll	                         boolean	  false	    设置为 true 则页面整体不能上下滚动。只在页面配置中有效，无法在 app.json 中设置
  // usingComponents	                       Object	    否	      页面自定义组件配置	1.6.3
// },
// todo ---------------------------  路由跳转  ----------------------------------
//    bindViewTap: function() {
//      wx.navigateTo({
//        url: '../logs/logs'
//      })
//    },
// <!-- app.wxss -->
// Bug & Tip
// tip：navigator-hover 默认为 {background-color: rgba(0, 0, 0, 0.1); opacity: 0.7;}, navigator 的子节点背景色应为透明色
// 示例代码
// .navigator-hover {
//   color:blue;
// }
// .other-navigator-hover {
//   color:red;
// }
// <!-- xxxxxx.wxml -->
// <view class="btn-area">
//   <navigator url="/page/navigate/navigate?title=navigate" hover-class="navigator-hover">跳转到新页面</navigator>
//   <navigator url="../../redirect/redirect/redirect?title=redirect" open-type="redirect" hover-class="other-navigator-hover">在当前页打开</navigator>
//   <navigator url="/page/index/index" open-type="switchTab" hover-class="other-navigator-hover">切换 Tab</navigator>
//   <navigator target="miniProgram" open-type="navigate" app-id="" path="" extra-data="" version="release">打开绑定的小程序</navigator>
// </view>
// navigator 基础库 1.0.0 开始支持，低版本需做兼容处理。
// 页面链接。
// 属性	                    类型	默认值	必填	说明	最低版本
// target	                 string	self	否	在哪个目标上发生跳转，默认当前小程序	2.0.7
// url	                   string		否	当前小程序内的跳转链接	1.0.0
// open-type	             string	navigate	否	跳转方式	1.0.0
// delta	                 number	1	否	当 open-type 为 'navigateBack' 时有效，表示回退的层数	1.0.0
// app-id	                 string		否	当target="miniProgram"时有效，要打开的小程序 appId	2.0.7
// path	                   string		否	当target="miniProgram"时有效，打开的页面路径，如果为空则打开首页	2.0.7
// extra-data	             object		否	当target="miniProgram"时有效，需要传递给目标小程序的数据，目标小程序可在 App.onLaunch()，App.onShow() 中获取到这份数据。详情	2.0.7
// version	               string	release	否	当target="miniProgram"时有效，要打开的小程序版本	2.0.7
// hover-class	           string	navigator-hover	否	指定点击时的样式类，当hover-class="none"时，没有点击态效果	1.0.0
// hover-stop-propagation	 boolean	false	否	指定是否阻止本节点的祖先节点出现点击态	1.5.0
// hover-start-time	       number	50	否	按住后多久出现点击态，单位毫秒	1.0.0
// hover-stay-time	       number	600	否	手指松开后点击态保留时间，单位毫秒	1.0.0
// bindsuccess	           string		 否	当target="miniProgram"时有效，跳转小程序成功	2.0.7
// bindfail	               string		 否	当target="miniProgram"时有效，跳转小程序失败	2.0.7
// bindcomplete	           string		否	当target="miniProgram"时有效，跳转小程序完成	2.0.7

// target 的合法值
// 值	                    说明	最低版本
// self	                  当前小程序
// miniProgram	          其它小程序

// open-type的合法值
// 值	                   说明	最低版本
// navigate	             对应 wx.navigateTo 或 wx.navigateToMiniProgram 的功能
// redirect	             对应 wx.redirectTo 的功能
// switchTab	             对应 wx.switchTab 的功能
// reLaunch	             对应 wx.reLaunch 的功能	1.1.0
// navigateBack	         对应 wx.navigateBack 的功能	1.1.0
// exit	                 退出小程序，target="miniProgram"时生效	2.1.0

// version 的合法值
// 值	                   说明	最低版本
// develop	             开发版
// trial	               体验版
// release	             正式版，仅在当前小程序为开发版或体验版时此参数有效；如果当前小程序是正式版，则打开的小程序必定是正式版

//todo ---------------------------  swiper轮播  ----------------------------------
// wxss
//  <swiper indicator-dots="{{indicatorDots}}"
//   autoplay="{{autoplay}}" interval="{{interval}}" duration="{{duration}}">
//   <block wx:for="{{imgUrls}}">
//     <swiper-item>
//       <image src="{{item}}" class="slide-image" width="355" height="150"/>
//     </swiper-item>
//   </block>
// </swiper>
// <button bindtap="changeIndicatorDots"> indicator-dots </button>
// <button bindtap="changeAutoplay"> autoplay </button>
// <slider bindchange="intervalChange" show-value min="500" max="2000"/>
// <slider bindchange="durationChange" show-value min="1000" max="10000"/> 

// js
// Page({
//   data: {
//     imgUrls: [
//       'https://images.unsplash.com/photo-1551334787-21e6bd3ab135?w=640',
//       'https://images.unsplash.com/photo-1551214012-84f95e060dee?w=640',
//       'https://images.unsplash.com/photo-1551446591-142875a901a1?w=640'
//     ],
//     indicatorDots: false,
//     autoplay: false,
//     interval: 5000,
//     duration: 1000
//   },
//   changeIndicatorDots: function(e) {
//     this.setData({
//       indicatorDots: !this.data.indicatorDots
//     })
//   },
//   changeAutoplay: function(e) {
//     this.setData({
//       autoplay: !this.data.autoplay
//     })
//   },
//   intervalChange: function(e) {
//     this.setData({
//       interval: e.detail.value
//     })
//   },
//   durationChange: function(e) {
//     this.setData({
//       duration: e.detail.value
//     })
//   }
// })

// 基础库 1.0.0 开始支持，低版本需做兼容处理。
// 滑块视图容器。其中只可放置swiper-item组件，否则会导致未定义的行为。

// 属性	                             类型	默认值	必填	说明	最低版本
// indicator-dots	                   boolean	false	否	是否显示面板指示点	1.0.0
// indicator-color	                 color	rgba(0, 0, 0, .3)	否	指示点颜色	1.1.0
// indicator-active-color	           color	#000000	否	当前选中的指示点颜色	1.1.0
// autoplay	                         boolean	false	否	是否自动切换	1.0.0
// current	                         number	0	否	当前所在滑块的 index	1.0.0
// interval	                         number	5000	否	自动切换时间间隔	1.0.0
// duration	                         number	500	否	滑动动画时长	1.0.0
// circular	                         boolean	false	否	是否采用衔接滑动	1.0.0
// vertical	                         boolean	false	否	滑动方向是否为纵向	1.0.0
// previous-margin	                 string	"0px"	否	前边距，可用于露出前一项的一小部分，接受 px 和 rpx 值	1.9.0
// next-margin	                     string	"0px"	否	后边距，可用于露出后一项的一小部分，接受 px 和 rpx 值	1.9.0
// display-multiple-items	           number	1	否	同时显示的滑块数量	1.9.0
// skip-hidden-item-layout	         boolean	false	否	是否跳过未显示的滑块布局，设为 true 可优化复杂情况下的滑动性能，但会丢失隐藏状态滑块的布局信息	1.9.0
// easing-function	string	         "default"	否	指定 swiper 切换缓动动画类型	2.6.5
// bindchange	eventhandle		         否	current 改变时会触发 change 事件，event.detail = {current, source}	1.0.0
// bindtransition	eventhandle		     否	swiper-item 的位置发生改变时会触发 transition 事件，event.detail = {dx: dx, dy: dy}	2.4.3
// bindanimationfinish	             eventhandle		否	动画结束时会触发 animationfinish 事件，event.detail 同上	1.9.0
// easing-function 的合法值

// 值	                               说明	最低版本
// default	                         默认缓动函数
// linear	                           线性动画
// easeInCubic	                     缓入动画
// easeOutCubic	                     缓出动画
// easeInOutCubic	                   缓入缓出动画
// change事件                        source 返回值

//todo ---------------------------  插件安装  ----------------------------------
// yarn add vant-weapp --production

//todo ---------------------------  组件  ----------------------------------
// import { VantComponent } from '../common/component';
// import { safeArea } from '../mixins/safe-area';
// VantComponent({
//     mixins: [safeArea()],
//     relation: {
//         name: 'tabbar-item',
//         type: 'descendant',
//         linked(target) {
//             this.children.push(target);
//             target.parent = this;
//             target.updateFromParent();
//         },
//         unlinked(target) {
//             this.children = this.children.filter((item) => item !== target);
//             this.updateChildren();
//         }
//     },
//     props: {
//         active: {
//             type: null,
//             observer: 'updateChildren'
//         },
//         activeColor: {
//             type: String,
//             observer: 'updateChildren'
//         },
//         inactiveColor: {
//             type: String,
//             observer: 'updateChildren'
//         },
//         fixed: {
//             type: Boolean,
//             value: true
//         },
//         border: {
//             type: Boolean,
//             value: true
//         },
//         zIndex: {
//             type: Number,
//             value: 1
//         }
//     },
//     beforeCreate() {
//         this.children = [];
//     },
//     methods: {
//         updateChildren() {
//             const { children } = this;
//             if (!Array.isArray(children) || !children.length) {
//                 return Promise.resolve();
//             }
//             return Promise.all(children.map((child) => child.updateFromParent()));
//         },
//         onChange(child) {
//             const index = this.children.indexOf(child);
//             const active = child.data.name || index;
//             if (active !== this.data.active) {
//                 this.$emit('change', active);
//             }
//         }
//     }
// });


//todo 微信提示授权
// wx.showModal({
//   title: '提示',
//   showCancel: false,
//   content: '同意授权',
//   success: function (res) { }
// })  